# coding=utf-8
import json

from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import F, Q
from django.utils import timezone
from wechatpy.pay import WeChatPayException

from fe_api.utils import view_funcs as common_view_funcs
from sutras import enums
from sutras import models
from sutras import serializers
from sutras.utils import tools


def check_wechat_notify_sign(params):
    wechat_pay = tools.init_wechat_pay()
    is_success = wechat_pay.check_signature(params)
    return is_success


def get_config_list():
    """
    获取抄写配置列表
    """
    templates = {
        # 排版方式
        "typeset": {
            "model": models.TypesetConfig,
            "serializer": serializers.TypesetConfigList,
        },
        # 纸张材质
        "material": {
            "model": models.MaterialConfig,
            "serializer": serializers.MaterialConfigList,
        },
        # 装订方式
        "bind": {
            "model": models.BindConfig,
            "serializer": serializers.BindConfigList,
        },
        # 字体颜色
        "font_color": {
            "model": models.FontColorConfig,
            "serializer": serializers.FontColorConfigList,
        },
    }
    config_list = {}
    for key, template in templates.items():
        queryset = template["model"].objects.all()
        dataset = template["serializer"](queryset, many=True).data
        config_list[key] = dataset
    return config_list


def get_order_preview(sutra_edition_id, user,
                      typeset_id, material_id, bind_id, font_color_id):
    """
    获取订单预览信息
    """
    try:
        sutra_edition = models.SutraEdition.objects.get(
            id=sutra_edition_id)
        typeset = models.TypesetConfig.objects.get(id=typeset_id)
        material = models.MaterialConfig.objects.get(id=material_id)
        bind = models.BindConfig.objects.get(id=bind_id)
        font_color = models.FontColorConfig.objects.get(id=font_color_id)
    except ObjectDoesNotExist:
        return None
    total_price = sutra_edition.price + typeset.price \
        + material.price + bind.price + material.price
    preview_data = {
        "total_price": total_price,

        "sutra_edition_name": sutra_edition.name,
        "sutra_edition_price": sutra_edition.price,

        "typeset_name": typeset.name,
        "typeset_price": typeset.price,
        "material_name": material.name,
        "material_price": material.price,
        "bind_name": bind.name,
        "bind_price": bind.price,
        "font_color_name": font_color.name,
        "font_color_price": font_color.price,
    }
    return preview_data


def create_order(sutra_edition_id, user,
                 typeset_id, material_id, bind_id, font_color_id):
    """
    创建订单
    """
    # 获取经书及各配置对象
    try:
        sutra_edition = models.SutraEdition.objects.get(
            id=sutra_edition_id)
        typeset = models.TypesetConfig.objects.get(id=typeset_id)
        material = models.MaterialConfig.objects.get(id=material_id)
        bind = models.BindConfig.objects.get(id=bind_id)
        font_color = models.FontColorConfig.objects.get(id=font_color_id)
    except ObjectDoesNotExist:
        return None

    # 创建用户格式
    user_layout = models.UserLayout.objects.create(
        user=user, typeset=typeset, material=material, bind=bind,
        font_color=font_color)

    # 创建抄写
    user_transcription = models.UserTranscription.objects.create(
        sutra_edition=sutra_edition,
        user=user,
        user_layout=user_layout,
        status=enums.UserTranscription.not_paid,
    )

    # 计算总金额
    total_price = sutra_edition.price + typeset.price \
        + material.price + bind.price + material.price
    # 生成订单号
    serial_num = tools.generate_order_serial_num()

    # 创建订单
    order_data = {
        "serial_num": serial_num,
        "user": user,
        "user_transcription": user_transcription,
        "sutra_edition": sutra_edition,
        "total_price": total_price,
        "total_should_pay": total_price,
        "status": enums.TranscriptionOrderStatus.not_paid,
        "pay_status": enums.TranscriptionOrderStatus.not_paid,
    }
    models.TranscriptionOrder.objects.create(**order_data)

    pay_desc = settings.TRANSCRIPT_WECHAT_ORDER_DESC.format(sutra_edition.name)
    wx_data = None

    if total_price:
        # 创建微信支付订单
        wechat_pay = tools.init_wechat_pay()
        try:
            res = wechat_pay.order.create(
                "JSAPI",
                pay_desc,
                int(total_price * 100),
                settings.WECHAT_TRANSCRIPT_PAY_NOTIFY_URL,
                user_id=user.open_id,
                out_trade_no=serial_num,
                attach=json.dumps({"order_id": serial_num}))
        except WeChatPayException as e:
            # TODO: 此处处理异常情况
            raise e
        prepay_id = res["prepay_id"]  # 预支付ID
        wx_data = wechat_pay.jsapi.get_jsapi_params(prepay_id)
    else:
        # 免费的，直接完成支付
        finish_pay(serial_num)

    return {
        "order_id": serial_num,
        "total_price": total_price,
        "user_transcription_id": user_transcription.id,
        "wx_data": wx_data,
    }


def finish_pay(order_id):
    """
    完成支付
    """
    # 只update状态未未支付的
    rows = models.TranscriptionOrder.objects.filter(
        serial_num=order_id,
        status=enums.TranscriptionOrderStatus.not_paid).update(
            status=enums.TranscriptionOrderStatus.paid,
            pay_status=enums.TranscriptionOrderPayStatus.paid)
    if not rows:
        # 不成功
        return False

    order = models.TranscriptionOrder.objects.filter(
        serial_num=order_id).first()

    # 初始化用户抄写状态
    user_transcription = order.user_transcription
    user_transcription.status = enums.UserTranscription.not_finished
    user_transcription.save()

    # 更新用户果业总花费
    user = order.user
    user_level = models.UserLevelInfo.objects.get(user=user)
    user_level.total_cost = F("total_cost") + order.total_price
    user_level.save()

    return True


def get_vow_list(offset, limit):
    """
    获取发愿文列表
    """
    vow_list = models.VowConfig.objects.order_by(
        "id")[offset:offset+limit].values_list("content", flat=True)
    return list(vow_list)


def update_vow(user, user_transcription_id, vow_text):
    """
    更新发愿文
    """
    user_transcription = models.UserTranscription.objects.filter(
        id=user_transcription_id,
        user=user).first()
    if not user_transcription \
            or user_transcription.status == enums.UserTranscription.finished:
        return False
    user_transcription.vow_text = vow_text
    user_transcription.vow_time = timezone.now()
    user_transcription.save()
    return True


def get_vow(user, user_transcription_id):
    """
    获取发愿文
    """
    user_transcription = models.UserTranscription.objects.filter(
        id=user_transcription_id,
        user=user).first()
    if not user_transcription:
        return False
    return user_transcription.vow_text


def get_sutra_edition_page(sutra_edition, page_num):
    page = models.SutraEditionPage.objects.filter(
        sutra_edition=sutra_edition, page_num=page_num).first()
    return page


def create_user_transcription_page(user_transcription, page_num):
    origin_page = get_sutra_edition_page(
        user_transcription.sutra_edition, page_num)
    if not origin_page:
        return None
    page = models.UserPageTranscription.objects.create(
        user_transcription=user_transcription,
        page_num=page_num,
        finish_char_num=0,
        total_char_num=origin_page.total_char_num,
        status=enums.UserPageTranscription.not_finished,
    )
    return page


def get_or_create_self_page(user_transcription):
    """
    获取或创建最新页(仅限自抄)

    流程：
        1. 如果没有抄写页，则创建第一页
        2. 如果最新页为自抄未完成，则返回改页
        3. 如果最新页完成，且小于总页数，则创建下一页
        4. 如果最新页等于总页数，则从第一页开始遍历，查看是否有未助抄完的，有则设置为废弃状态，并新建自抄页
    """
    total_page_num = user_transcription.sutra_edition.total_page_num

    latest_page = models.UserPageTranscription.objects.filter(
        user_transcription=user_transcription).exclude(
            status=enums.UserPageTranscription.abandoned).order_by(
                "-page_num").first()

    # 还没抄过，则创建第一页
    if not latest_page:
        first_page_num = 1
        latest_page = create_user_transcription_page(
            user_transcription, first_page_num)
        return latest_page

    # 最新页是自抄的，且未抄写完，则直接返回该页
    if (not latest_page.assistant_user and
            latest_page.status == enums.UserPageTranscription.not_finished):
        return latest_page

    # 之后还有可抄页码，则创建下一页
    if latest_page.page_num < total_page_num:
        new_page_num = latest_page.page_num + 1
        latest_page = create_user_transcription_page(
            user_transcription, new_page_num)
        return latest_page

    # 找到最早的未完成的助抄页，废弃之，并创建该页的自抄页
    unfinished_assistant_page = models.UserPageTranscription.objects.filter(
        user_transcription=user_transcription,
        assistant_user__isnull=False,
        status=enums.UserPageTranscription.not_finished).order_by(
            "page_num").first()
    if unfinished_assistant_page:
        unfinished_assistant_page.status = enums.UserPageTranscription.abandoned
        unfinished_assistant_page.save()
        create_user_transcription_page(
            user_transcription, unfinished_assistant_page.page_num)

    return latest_page


def get_assistant_page(assistant_user, user_transcription):
    latest_page = models.UserPageTranscription.objects.filter(
        user_transcription=user_transcription,
        assistant_user=assistant_user,
        status=enums.UserPageTranscription.not_finished
        ).order_by("page_num").first()
    return latest_page


def get_progress(user, user_transcription_id):
    """
    获取抄写进度
    """
    user_transcription = models.UserTranscription.objects.filter(
        id=user_transcription_id).first()
    if not user_transcription:
        return None

    if user_transcription.user == user:
        # 自抄
        latest_page = get_or_create_self_page(user_transcription)
        _type = 0
    else:
        # 助抄
        latest_page = get_assistant_page(
            user, user_transcription)
        # 有助抄关系
        _type = 1

    if not latest_page:
        return False
    page_num = latest_page.page_num

    progress_data = {
        "status": user_transcription.status,
        "char_index": latest_page.finish_char_num,
        "page_total_char_num": latest_page.total_char_num,
        "page_num": page_num,
        "total_page_num": user_transcription.sutra_edition.total_page_num,
        "type": _type,
    }

    layout_config = user_transcription.user_layout
    progress_data["layout_config"] = {
        "font_color": layout_config.font_color.content,
        "material_url": layout_config.material.content,
    }

    return progress_data


def get_page_data(sutra_edition_id, page_num, user_transcription_id=None):
    """
    获取抄写页数据
    """
    sutra_edition_page = models.SutraEditionPage.objects.filter(
        sutra_edition_id=sutra_edition_id,
        page_num=page_num).first()

    if not sutra_edition_page:
        return None

    char_objs = models.SutraEditionChar.objects.filter(
        # sutra_edition=user_transcription.sutra_edition,
        page=sutra_edition_page
        ).order_by("index")

    page_data = {
        "layout_config": {},
        "chars": [],
    }
    # 获取字数据
    for char_obj in char_objs:
        img_path = settings.PAGE_WORD_URL.format(
                sutra_edition_id, page_num) + char_obj.img_url
        img_url = settings.SELF_DOMAIN + img_path
        page_data["chars"].append({
            "index": char_obj.index,
            "text": char_obj.text,
            # 去除文本中已有的中括号
            "x_positions": sorted(char_obj.x_positions[1:-1].split(",")),
            "y_positions": sorted(char_obj.y_positions[1:-1].split(",")),
            "img_url": img_url,
        })

    # 如果有抄写ID，则获取抄写配置
    user_transcription = models.UserTranscription.objects.filter(
        id=user_transcription_id).first()
    if user_transcription:
        layout_config = user_transcription.user_layout
        page_data["layout_config"] = {
            "font_color": layout_config.font_color.content,
            "material_url": layout_config.material.content,
        }

    return page_data


def submit_char(user, user_transcription_id, page_num, char_index):
    """
    提交手写字
    """
    user_transcription = models.UserTranscription.objects.filter(
        id=user_transcription_id).first()
    if not user_transcription:
        return False

    if user == user_transcription.user:
        # 自抄
        page = get_or_create_self_page(user_transcription)
        is_assistant = False
        owner_user_level = models.UserLevelInfo.objects.get(user=user)
        assistant_user_level = None

    else:
        # 助抄
        page = models.UserPageTranscription.objects.filter(
            user_transcription=user_transcription,
            page_num=page_num,
            assistant_user=user).exclude(
                status=enums.UserPageTranscription.abandoned).first()
        is_assistant = True
        owner_user_level = models.UserLevelInfo.objects.get(
            user=user_transcription.user)
        assistant_user_level = models.UserLevelInfo.objects.get(user=user)

    if not page:
        return False
    if page.page_num != page_num:
        return False
    if page.finish_char_num != char_index:
        return False

    # 当前页已抄字数
    user_transcription.finish_char_num = F("finish_char_num") + 1
    user_transcription.save()

    page.finish_char_num = F("finish_char_num") + 1
    page.save()

    page.refresh_from_db()

    # 更新用户果业字数
    if is_assistant:
        assistant_user_level.finish_char_num = F("finish_char_num") + 1
    else:
        owner_user_level.finish_char_num = F("finish_char_num") + 1

    if page.finish_char_num >= page.total_char_num:

        # 如果当前页已抄完，则更改page状态，新建用户抄写页
        page.status = enums.UserPageTranscription.finished
        page.save()
        new_page_num = page_num + 1

        # 更新用户果业页数
        owner_user_level.finish_page_num = F("finish_page_num") + 1
        if is_assistant:
            owner_user_level.assist_page_num = F("assist_page_num") + 1

        # 如果还有还有下一页
        if user_transcription.sutra_edition.total_page_num >= new_page_num:
            if not is_assistant:
                # 非助抄，则创建下一页
                create_user_transcription_page(
                    user_transcription, new_page_num)
        # 没有下一页了，则看是否所有页均已抄完
        else:
            total_page_num = user_transcription.sutra_edition.total_page_num
            finished_page_num = models.UserPageTranscription.objects.filter(
                user_transcription=user_transcription,
                status=enums.UserPageTranscription.finished).count()
            # 如果所有页都已抄完，则标记抄写为完成状态
            if finished_page_num >= total_page_num:
                user_transcription.status \
                    = enums.UserPageTranscription.finished
                user_transcription.save()

                # 更新用户果业本数
                owner_user_level.finish_book_num = F("finish_book_num") + 1

    # 用户果业入库
    owner_user_level.save()
    if is_assistant:
        assistant_user_level.save()

    return True


def get_assistants(user_transcription):
    """
    获取助抄人列表
    """
    assistant_ids = models.AssistantRelation.objects.filter(
        user_transcription=user_transcription).values_list(
            "assistant_user_id", flat=True)
    assistants = models.CustomUser.objects.filter(id__in=assistant_ids)
    return assistants


def get_assistant_infos(user_transcription):
    assistant_objs = get_assistants(user_transcription)
    open_ids = [assistant_obj.open_id
                for assistant_obj in assistant_objs]
    wx_infos = tools.get_wx_user_infos(open_ids)
    user_infos = []

    for assistant_obj in assistant_objs:
        open_id = assistant_obj.open_id
        wx_info = wx_infos.get(open_id)
        user_info = {
            "uid": assistant_obj.uid,
            "name": wx_info["nickname"],
            "avatar_url": wx_info["headimgurl"],
        }
        user_infos.append(user_info)
    return user_infos


def finish_transcription(user, user_transcription_id,
                         signature_img=None, signature_text=None):
    """
    完成抄写
    """
    user_transcription = models.UserTranscription.objects.filter(
        id=user_transcription_id, user=user).first()

    # 用户没抄写过该经书版本
    if not user_transcription:
        return False, None

    # 该抄写已完成过
    # if user_transcription.status == enums.UserTranscription.finished:
    #     return False, None

    total_page_num = user_transcription.sutra_edition.total_page_num
    finished_page_num = models.UserPageTranscription.objects.filter(
        user_transcription=user_transcription,
        status=enums.UserPageTranscription.finished).count()

    # 已完成的页数未达到总数
    if total_page_num > finished_page_num:
        return False, None

    if signature_img:
        signature_img_url = tools.upload_file(signature_img)
        user_transcription.signature_img_url = signature_img_url
    else:
        user_transcription.signature_text = signature_text
    user_transcription.status = enums.UserTranscription.finished
    user_transcription.finish_time = timezone.now()
    user_transcription.save()

    assistants = get_assistant_infos(user_transcription)

    finish_data = {
        "assistants": assistants,
        "sutra_edition_info": {
            "name": user_transcription.sutra_edition.name,
            "cover_url": user_transcription.sutra_edition.cover_url,
            "total_char_num": user_transcription.sutra_edition.total_char_num,
        },
        "finish_time": user_transcription.finish_time,
    }

    return True, finish_data


def get_sutra_editions(user, type, offset, limit):
    """
    获取用户的经书版本列表

    请求参数：
        type: 0: 未抄完 1: 已抄完 2: 同修中
    """
    if type == 0:
        user_transcription_objs = models.UserTranscription.objects.filter(
            user=user,
            status=enums.UserTranscription.not_finished
        )[offset: limit + offset]
    elif type == 1:
        user_transcription_objs = models.UserTranscription.objects.filter(
            user=user,
            status=enums.UserTranscription.finished
            )[offset: limit + offset]
    elif type == 2:
        condition = Q(owner_user=user) | Q(assistant_user=user)
        user_transcription_ids = models.AssistantRelation.objects.filter(
            condition)[offset: limit + offset].values_list(
                "user_transcription_id", flat=True)
        user_transcription_objs = models.UserTranscription.objects.filter(
            id__in=user_transcription_ids)

    sutra_editions = []
    for user_transcription_obj in user_transcription_objs:
        sutra_edition = user_transcription_obj.sutra_edition
        cover_url = "{0}{1}".format(
            settings.SELF_DOMAIN, sutra_edition.cover_url)
        sutra_editions.append({
            "id": sutra_edition.id,
            "user_transcription_id": user_transcription_obj.id,
            "name": sutra_edition.name,
            "cover_url": cover_url,
        })
    return sutra_editions


def get_user_transcription_detail(user, user_transcription_id, type):
    """
    获取经书抄写详情

    请求参数：
        type: 0: 自抄 1: 助抄
    """
    user_transcription = None
    if type == 0:
        user_transcription = models.UserTranscription.objects.filter(
            id=user_transcription_id).first()
    elif type == 1:
        relation = models.AssistantRelation.objects.filter(
            user_transcription_id=user_transcription_id,
            assistant_user=user).first()
        user_transcription = relation.user_transcription if relation else None
    if not user_transcription:
        return None

    assistants = get_assistant_infos(user_transcription)

    detail_data = {
        "sutra_info": {
            "cover_url": user_transcription.sutra_edition.cover_url,
            "name": user_transcription.sutra_edition.name,
            "total_char_num": user_transcription.sutra_edition.total_char_num,
        },
        "start_time": user_transcription.create_time,
        "end_time": user_transcription.finish_time,
        "vow_time": user_transcription.vow_time,
        "finish_char_num": user_transcription.finish_char_num,
        "vow_text": user_transcription.vow_text,
        "assistants": assistants,
    }
    return detail_data
